﻿// -------------------------------------------------------------------------
//    @FileName         :    NFPackageServiceTest.cpp
//    @Author           :    Gao.Yi
//    @Date             :    2025-10-14
//    @Email			:    445267987@qq.com
//    @Module           :    NFPackageServiceTest
//    @Desc             :    NFServicePackage unit test implementation
//
// -------------------------------------------------------------------------

#include "NFComm/NFCore/NFPlatform.h"

#ifdef NF_DEBUG_MODE
#ifdef NF_STATIC_PLUGIN

#include "NFPackageServiceTest.h"
#include "NFServicePackage.h"
#include "NFPlayer.h"
#include "NFPackagePart.h"
#include "NFLogicCommon/BagPage/NFBagPageOpDefine.h"
#include "DescStore/ItemDesc.h"
#include "NFLogicCommon/BagPage/NFBagDefine.h"
#include "NFBagPageOpMgr.h"
#include "NFLogicCommon/BagPage/NFBagPageOp.h"
#include <chrono>

// ================================================================================
// Static member initialization
// ================================================================================

NFPlayer* PackageServiceTestFixture::s_pPlayer = nullptr;
std::vector<int> PackageServiceTestFixture::s_vecItemIDs;
std::vector<int> PackageServiceTestFixture::s_vecEquipIDs;
std::vector<int> PackageServiceTestFixture::s_vecMoneys;
std::vector<int> PackageServiceTestFixture::s_vecBagTypes = g_personAllOpBagType;

// ================================================================================
// Test fixture implementation
// ================================================================================

void PackageServiceTestFixture::SetUpTestSuite()
{
    // Test suite initialization
    // Note: Assumes there is a valid player object in GM command
}

void PackageServiceTestFixture::TearDownTestSuite()
{
    // Test suite cleanup
}

void PackageServiceTestFixture::SetUp()
{
    // Initialization before each test case
}

void PackageServiceTestFixture::TearDown()
{
    // Cleanup after each test case
}

// ================================================================================
// Test cases: Bag page operations
// ================================================================================

/**
 * @brief Test get bag page
 */
TEST_F(PackageServiceTestFixture, TestGetBagPage)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    // 测试获取装备背包（EN_BPT_EQUIP）
    NFBagPage* pBagPage = NFServicePackage::GetBagPage(s_pPlayer, EN_BPT_EQUIP);
    EXPECT_NE(pBagPage, nullptr) << "Failed to get bag page";

    // 测试获取道具背包（EN_BPT_PROP）
    NFBagPage* pPropPage = NFServicePackage::GetBagPage(s_pPlayer, EN_BPT_PROP);
    EXPECT_NE(pPropPage, nullptr) << "Failed to get prop bag page";
}

// ================================================================================
// Test cases: Money operations
// ================================================================================

/**
 * @brief Test get money object
 */
TEST_F(PackageServiceTestFixture, TestGetMoney)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecMoneys.empty())
    {
        // Skip test if no valid money types available
        return;
    }

    // Use random money type
    int iMoneyType = RandomMoneyType();
    Money* pMoney = NFServicePackage::GetMoney(s_pPlayer, iMoneyType);
    EXPECT_NE(pMoney, nullptr) << "Failed to get money object for type: " << iMoneyType;
}

/**
 * @brief Test get money number
 */
TEST_F(PackageServiceTestFixture, TestGetMoneyNumber)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecMoneys.empty())
    {
        // Skip test if no valid money types available
        return;
    }

    // Use random money type
    int iMoneyType = RandomMoneyType();
    int64_t llMoney = NFServicePackage::GetMoneyNumber(s_pPlayer, iMoneyType);
    EXPECT_GE(llMoney, 0) << "Money number should be non-negative for type: " << iMoneyType;
}

/**
 * @brief Test set money number
 */
TEST_F(PackageServiceTestFixture, TestSetMoneyNumber)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecMoneys.empty())
    {
        // Skip test if no valid money types available
        return;
    }

    // Use random money type
    int iMoneyType = RandomMoneyType();

    // Record original money amount
    int64_t llOriginalMoney = NFServicePackage::GetMoneyNumber(s_pPlayer, iMoneyType);

    // Set new money amount
    int64_t llNewMoney = llOriginalMoney + 10000;
    int iRetCode = NFServicePackage::SetMoneyNumber(s_pPlayer, iMoneyType, llNewMoney);
    EXPECT_EQ(iRetCode, 0) << "Failed to set money number for type: " << iMoneyType;

    // Verify if set successfully
    int64_t llCurrentMoney = NFServicePackage::GetMoneyNumber(s_pPlayer, iMoneyType);
    EXPECT_EQ(llCurrentMoney, llNewMoney) << "Money number not set correctly";

    // Restore original money amount
    NFServicePackage::SetMoneyNumber(s_pPlayer, iMoneyType, llOriginalMoney);
}

// ================================================================================
// Test cases: Add item operations
// ================================================================================

/**
 * @brief Test add item to bag (single item)
 */
TEST_F(PackageServiceTestFixture, TestAddToBag_SingleItem)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID
    int iItemID = RandomItemId();

    // Get suitable bag type for this item
    int iSuitableBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iSuitableBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    // Check bag space
    NFPackagePart* pPackagePart = s_pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    ASSERT_NE(pPackagePart, nullptr) << "Failed to get package part";

    int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
    if (iEmptyGridNum < 5)
    {
        // Clear bag
        NFServicePackage::DelAllItemByItemID(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iSuitableBagType);
    }

    WillAddItemData stItemData;
    stItemData.id = iItemID;
    stItemData.quality = 1;
    stItemData.role_bind = false;

    int iAddNum = 10;
    int iActualAddNum = 0;

    iRetCode = NFServicePackage::AddToBag(s_pPlayer, proto_ff::EN_ICR_GM, stItemData, iAddNum, false, &iActualAddNum);

    if (iRetCode == 0)
    {
        EXPECT_EQ(iActualAddNum, iAddNum) << "Added item count mismatch for item: " << iItemID;
    }
}

/**
 * @brief Test add items to bag (multiple items)
 */
TEST_F(PackageServiceTestFixture, TestAddToBag_MultipleItems)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.size() < 3)
    {
        // Skip test if not enough item IDs available
        return;
    }

    // Check bag space for each item
    NFPackagePart* pPackagePart = s_pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    ASSERT_NE(pPackagePart, nullptr) << "Failed to get package part";

    // Clear bags for items to be added
    for (int i = 0; i < 3 && i < (int)s_vecItemIDs.size(); i++)
    {
        int iSuitableBagType = 0;
        int iRetCode = NFItemUtil::GetSuitableBag(s_vecItemIDs[i], proto_ff::EN_ICR_GM, iSuitableBagType);
        if (iRetCode == 0)
        {
            int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
            if (iEmptyGridNum < 5)
            {
                NFServicePackage::DelAllItemByItemID(s_pPlayer, proto_ff::EN_ICR_GM, s_vecItemIDs[i], iSuitableBagType);
            }
        }
    }

    std::vector<WillAddItemData> vecItems;
    std::vector<int> vecNums;
    std::vector<int> vecAddedNums;

    // Use random item IDs
    for (int i = 0; i < 3; i++)
    {
        WillAddItemData stItemData;
        stItemData.id = RandomItemId();
        stItemData.quality = 1;
        vecItems.push_back(stItemData);
        vecNums.push_back(5);
    }

    int iRetCode = NFServicePackage::AddToBag(s_pPlayer, proto_ff::EN_ICR_GM, vecItems, vecNums, false, &vecAddedNums);

    if (iRetCode == 0)
    {
        EXPECT_EQ(vecAddedNums.size(), vecItems.size()) << "Added items count mismatch";
    }
}

/**
 * @brief Test add item to specified bag page
 */
TEST_F(PackageServiceTestFixture, TestAddToBagPage)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID
    int iItemID = RandomItemId();

    // Get suitable bag type for this item
    int iSuitableBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iSuitableBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    // Check bag space
    NFPackagePart* pPackagePart = s_pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    ASSERT_NE(pPackagePart, nullptr) << "Failed to get package part";

    int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
    if (iEmptyGridNum < 5)
    {
        NFServicePackage::DelAllItemByItemID(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iSuitableBagType);
    }

    WillAddItemData stItemData;
    stItemData.id = iItemID;
    stItemData.quality = 1;

    int iAddNum = 5;
    int iActualAddNum = 0;

    iRetCode = NFServicePackage::AddToBagPage(s_pPlayer, proto_ff::EN_ICR_GM, stItemData, iAddNum, iSuitableBagType, false, &iActualAddNum);

    if (iRetCode == 0)
    {
        EXPECT_EQ(iActualAddNum, iAddNum) << "Added item count mismatch for item: " << iItemID;
    }
}

/**
 * @brief Test add item by ID and number (test stacking)
 */
TEST_F(PackageServiceTestFixture, TestAddByItemIDAndNum)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID
    int iItemID = RandomItemId();

    // Get suitable bag type for this item
    int iSuitableBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iSuitableBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    // Check bag space
    NFPackagePart* pPackagePart = s_pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    ASSERT_NE(pPackagePart, nullptr) << "Failed to get package part";

    int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
    if (iEmptyGridNum < 5)
    {
        NFServicePackage::DelAllItemByItemID(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iSuitableBagType);
    }

    // First add
    int iNum = 10;
    iRetCode = NFServicePackage::AddByItemIDAndNum(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iNum, iSuitableBagType, EN_BT_AUTO);

    if (iRetCode == 0)
    {
        int iTotalNum1 = 0;
        NFServicePackage::GetItemTotalNum(s_pPlayer, iItemID, iTotalNum1);
        EXPECT_GE(iTotalNum1, iNum) << "Item total number should be at least added number";

        // Test stacking: add same item again
        int iNum2 = 15;
        iRetCode = NFServicePackage::AddByItemIDAndNum(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iNum2, iSuitableBagType, EN_BT_AUTO);
        if (iRetCode == 0)
        {
            int iTotalNum2 = 0;
            NFServicePackage::GetItemTotalNum(s_pPlayer, iItemID, iTotalNum2);
            EXPECT_GE(iTotalNum2, iTotalNum1 + iNum2) << "Item should stack correctly";
        }
    }
}

/**
 * @brief Test add multiple items (Item list)
 */
TEST_F(PackageServiceTestFixture, TestAddItems)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID
    int iItemID = RandomItemId();

    // Get suitable bag type for this item
    int iSuitableBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iSuitableBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    // Check bag space
    NFPackagePart* pPackagePart = s_pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    ASSERT_NE(pPackagePart, nullptr) << "Failed to get package part";

    int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
    if (iEmptyGridNum < 5)
    {
        NFServicePackage::DelAllItemByItemID(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iSuitableBagType);
    }

    std::vector<Item> vecItems;
    std::vector<Item> vecLeftItems;

    // Prepare test items
    Item stItem;
    stItem.id = iItemID;
    stItem.value = 5;
    vecItems.push_back(stItem);

    iRetCode = NFServicePackage::AddItems(s_pPlayer, vecItems, proto_ff::EN_ICR_GM, false, &vecLeftItems, false);

    if (iRetCode == 0)
    {
        EXPECT_LE(vecLeftItems.size(), vecItems.size()) << "Left items should not exceed added items";
    }
}

/**
 * @brief Test add by item object
 */
TEST_F(PackageServiceTestFixture, TestAddByItem)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID
    int iItemID = RandomItemId();

    // Get suitable bag type for this item
    int iSuitableBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iSuitableBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    // Check bag space
    NFPackagePart* pPackagePart = s_pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    ASSERT_NE(pPackagePart, nullptr) << "Failed to get package part";

    int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
    if (iEmptyGridNum < 5)
    {
        NFServicePackage::DelAllItemByItemID(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iSuitableBagType);
    }

    NFGridItem item;
    item.SetItemID(iItemID);
    item.SetNumber(10);
    item.SetQuality(1);

    iRetCode = NFServicePackage::AddByItem(s_pPlayer, proto_ff::EN_ICR_GM, &item, true);

    // 验证返回码
    EXPECT_TRUE(iRetCode == 0 || iRetCode < 0) << "Return code should be valid";
}

// ================================================================================
// Test cases: Get item operations
// ================================================================================

/**
 * @brief Test get bag item total number
 */
TEST_F(PackageServiceTestFixture, TestGetBagItemTotalNumByItemID)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID并先添加一些
    int iItemID = RandomItemId();
    int iRetCode = NFServicePackage::AddByItemIDAndNum(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, 5, 0, EN_BT_AUTO);
    if (iRetCode != 0)
    {
        // Skip test if failed to add item
        return;
    }

    int iTotalNum = 0;
    iRetCode = NFServicePackage::GetAllItemTotalNum(s_pPlayer, iItemID, iTotalNum);
    EXPECT_EQ(iRetCode, 0) << "Failed to get bag item total number for item: " << iItemID;
    EXPECT_GE(iTotalNum, 0) << "Item total number should be non-negative";
}

/**
 * @brief Test get suitable bag item total number
 */
TEST_F(PackageServiceTestFixture, TestGetSuitableBagItemTotalNumByItemID)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID
    int iItemID = RandomItemId();
    int iRetCode = NFServicePackage::AddByItemIDAndNum(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, 5, 0, EN_BT_AUTO);
    if (iRetCode != 0)
    {
        // Skip test if failed to add item
        return;
    }

    int iTotalNum = 0;
    iRetCode = NFServicePackage::GetItemTotalNum(s_pPlayer, iItemID, iTotalNum);
    EXPECT_EQ(iRetCode, 0) << "Failed to get suitable bag item total number for item: " << iItemID;
    EXPECT_GE(iTotalNum, 0) << "Item total number should be non-negative";
}

/**
 * @brief Test get item total number (reference version)
 */
TEST_F(PackageServiceTestFixture, TestGetItemTotalNum_WithRef)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID
    int iItemID = RandomItemId();
    int iRetCode = NFServicePackage::AddByItemIDAndNum(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, 5, 0, EN_BT_AUTO);
    if (iRetCode != 0)
    {
        // Skip test if failed to add item
        return;
    }

    int iTotalNum = 0;
    iRetCode = NFServicePackage::GetItemTotalNum(s_pPlayer, iItemID, iTotalNum);
    EXPECT_EQ(iRetCode, 0) << "Failed to get item total number for item: " << iItemID;
    EXPECT_GE(iTotalNum, 0) << "Item total number should be non-negative";
}

/**
 * @brief 测试获取物品总数量（返回值版本）
 */
TEST_F(PackageServiceTestFixture, TestGetItemTotalNum_ReturnValue)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID
    int iItemID = RandomItemId();
    int iRetCode = NFServicePackage::AddByItemIDAndNum(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, 5, 0, EN_BT_AUTO);
    if (iRetCode != 0)
    {
        // Skip test if failed to add item
        return;
    }

    int iTotalNum = NFServicePackage::GetItemTotalNum(s_pPlayer, iItemID);
    EXPECT_GE(iTotalNum, 0) << "Item total number should be non-negative";
}

/**
 * @brief 测试通过格子索引获取物品
 */
TEST_F(PackageServiceTestFixture, TestGetItem_ByGrid)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    int iBagType = EN_BPT_PROP; // 道具背包
    int iGridIndex = 0;
    NFGridItem itemOut;

    int iRetCode = NFServicePackage::GetItem(s_pPlayer, iBagType, iGridIndex, &itemOut);

    // 验证返回码和物品数据
    EXPECT_TRUE(iRetCode == 0 || iRetCode < 0) << "Return code should be valid";
}

/**
 * @brief 测试获取背包所有物品
 */
TEST_F(PackageServiceTestFixture, TestGetItem_AllItems)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    int iBagType = EN_BPT_PROP; // 道具背包
    std::vector<NFGridItem> vecItems;

    int iRetCode = NFServicePackage::GetItem(s_pPlayer, iBagType, vecItems);

    EXPECT_TRUE(iRetCode >= 0 || iRetCode < 0) << "Return code should be valid";
}

/**
 * @brief 测试通过UUID获取物品（引用版本）
 */
TEST_F(PackageServiceTestFixture, TestGetItemByUUID_WithRef)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    int iBagType = EN_BPT_PROP; // 道具背包
    uint64_t ullUUID = 123456; // 测试UUID
    NFGridItem itemOut;

    int iRetCode = NFServicePackage::GetItemByUUID(s_pPlayer, iBagType, ullUUID, &itemOut);

    // 可能找不到该UUID的物品，这是正常的
    EXPECT_TRUE(iRetCode == 0 || iRetCode < 0) << "Return code should be valid";
}

/**
 * @brief 测试通过UUID获取物品（指针版本）
 */
TEST_F(PackageServiceTestFixture, TestGetItemByUUID_Pointer)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    int iBagType = EN_BPT_PROP; // 道具背包
    uint64_t ullUUID = 123456;

    NFGridItem* pItem = NFServicePackage::GetItemByUUID(s_pPlayer, iBagType, ullUUID);

    // 可能为空，这是正常的
    // 仅验证函数调用不会崩溃
}

/**
 * @brief 测试通过物品ID获取物品
 */
TEST_F(PackageServiceTestFixture, TestGetItemByItemID)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID并先添加
    int iItemID = RandomItemId();
    int iBagType = EN_BPT_PROP; // 道具背包
    int iRetCode = NFServicePackage::AddByItemIDAndNum(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, 5, iBagType, EN_BT_AUTO);
    if (iRetCode != 0)
    {
        // Skip test if failed to add item
        return;
    }

    NFGridItem itemOut;
    iRetCode = NFServicePackage::GetItemByItemId(s_pPlayer, iBagType, iItemID, &itemOut);

    EXPECT_TRUE(iRetCode == 0 || iRetCode < 0) << "Return code should be valid for item: " << iItemID;
}

/**
 * @brief 测试通过物品ID和UUID获取物品（引用版本）
 */
TEST_F(PackageServiceTestFixture, TestGetItemByItemIdAndUUID_WithRef)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    int iItemID = 1; // 使用实际物品ID
    uint64_t ullUUID = 123456;
    NFGridItem itemOut;

    int iRetCode = NFServicePackage::GetItemByItemIdAndUUID(s_pPlayer, iItemID, ullUUID, &itemOut);

    EXPECT_TRUE(iRetCode == 0 || iRetCode < 0) << "Return code should be valid";
}

/**
 * @brief 测试通过物品ID和UUID获取物品（指针版本）
 */
TEST_F(PackageServiceTestFixture, TestGetItemByItemIdAndUUID_Pointer)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    int iItemID = 1; // 使用实际物品ID
    uint64_t ullUUID = 123456;

    NFGridItem* pItem = NFServicePackage::GetItemByItemIdAndUUID(s_pPlayer, iItemID, ullUUID);

    // 可能为空，这是正常的
}

// ================================================================================
// Test cases: Delete item operations
// ================================================================================

/**
 * @brief 测试批量删除物品
 */
TEST_F(PackageServiceTestFixture, TestDelItems)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID
    int iItemID = RandomItemId();

    // Get suitable bag type for this item
    int iSuitableBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iSuitableBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    // Check bag space
    NFPackagePart* pPackagePart = s_pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    ASSERT_NE(pPackagePart, nullptr) << "Failed to get package part";

    int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
    if (iEmptyGridNum < 5)
    {
        NFServicePackage::DelAllItemByItemID(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iSuitableBagType);
    }

    // 先添加一些物品用于测试删除
    int iAddNum = 20;
    iRetCode = NFServicePackage::AddByItemIDAndNum(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iAddNum, iSuitableBagType, EN_BT_AUTO);
    if (iRetCode != 0)
    {
        // Skip test if failed to add item
        return;
    }

    // 准备删除数据
    std::vector<DelItemData> vecDelItems;
    vecDelItems.push_back(DelItemData());
    DelItemData& delData = vecDelItems.back();
    delData.m_iWareID = iItemID;
    delData.m_iWantDelNum = 10;

    iRetCode = NFServicePackage::DelItems(s_pPlayer, vecDelItems, proto_ff::EN_ICR_GM, true);

    if (iRetCode == 0)
    {
        EXPECT_GT(delData.m_iRealDelNum, 0) << "Should delete some items";
    }
}

/**
 * @brief 测试通过物品ID和数量删除物品
 */
TEST_F(PackageServiceTestFixture, TestDelItemByItemIDAndNum)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID
    int iItemID = RandomItemId();

    // Get suitable bag type for this item
    int iSuitableBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iSuitableBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    // Check bag space
    NFPackagePart* pPackagePart = s_pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    ASSERT_NE(pPackagePart, nullptr) << "Failed to get package part";

    int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
    if (iEmptyGridNum < 5)
    {
        NFServicePackage::DelAllItemByItemID(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iSuitableBagType);
    }

    // 先添加物品
    int iAddNum = 30;
    iRetCode = NFServicePackage::AddByItemIDAndNum(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iAddNum, iSuitableBagType, EN_BT_AUTO);
    if (iRetCode != 0)
    {
        // Skip test if failed to add item
        return;
    }

    // 删除部分物品
    int iDelNum = 15;
    int iActualDelNum = 0;
    iRetCode = NFServicePackage::DelItemByItemIDAndNum(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iDelNum, &iActualDelNum);

    if (iRetCode == 0)
    {
        EXPECT_GT(iActualDelNum, 0) << "Should delete some items";
        EXPECT_LE(iActualDelNum, iDelNum) << "Deleted count should not exceed requested";
    }
}

/**
 * @brief 测试删除所有指定ID的物品
 */
TEST_F(PackageServiceTestFixture, TestDelAllItemByItemID)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID
    int iItemID = RandomItemId();

    // Get suitable bag type for this item
    int iSuitableBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iSuitableBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    // Check bag space
    NFPackagePart* pPackagePart = s_pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    ASSERT_NE(pPackagePart, nullptr) << "Failed to get package part";

    int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
    if (iEmptyGridNum < 5)
    {
        NFServicePackage::DelAllItemByItemID(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iSuitableBagType);
    }

    // 先添加物品
    int iAddNum = 25;
    iRetCode = NFServicePackage::AddByItemIDAndNum(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iAddNum, iSuitableBagType, EN_BT_AUTO);
    if (iRetCode != 0)
    {
        // Skip test if failed to add item
        return;
    }

    // 删除所有该物品
    iRetCode = NFServicePackage::DelAllItemByItemID(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iSuitableBagType);

    if (iRetCode == 0)
    {
        // 验证物品已被删除
        int iTotalNum = 0;
        NFServicePackage::GetAllItemTotalNum(s_pPlayer, iItemID, iTotalNum);
        EXPECT_EQ(iTotalNum, 0) << "All items should be deleted";
    }
}

/**
 * @brief 测试通过格子索引和数量删除物品
 */
TEST_F(PackageServiceTestFixture, TestDelItemByNumWithGrid)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID
    int iItemID = RandomItemId();

    // Get suitable bag type for this item
    int iSuitableBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iSuitableBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    // Check bag space
    NFPackagePart* pPackagePart = s_pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    ASSERT_NE(pPackagePart, nullptr) << "Failed to get package part";

    int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
    if (iEmptyGridNum < 5)
    {
        NFServicePackage::DelAllItemByItemID(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iSuitableBagType);
    }

    // 先添加物品到特定格子
    int iAddNum = 20;
    iRetCode = NFServicePackage::AddByItemIDAndNum(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iAddNum, iSuitableBagType, EN_BT_AUTO);
    if (iRetCode != 0)
    {
        // Skip test if failed to add item
        return;
    }

    // 通过格子删除部分物品
    int iGridIndex = 0;
    int iDelNum = 10;

    iRetCode = NFServicePackage::DelItemByNumWithGrid(s_pPlayer, proto_ff::EN_ICR_GM, iGridIndex, iDelNum, iSuitableBagType);

    EXPECT_TRUE(iRetCode == 0 || iRetCode < 0) << "Return code should be valid";
}

/**
 * @brief 测试通过格子索引删除物品
 */
TEST_F(PackageServiceTestFixture, TestDelItemByGrid)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    if (s_vecItemIDs.empty())
    {
        // Skip test if no valid item IDs available
        return;
    }

    // Use random item ID
    int iItemID = RandomItemId();

    // Get suitable bag type for this item
    int iSuitableBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iSuitableBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    // Check bag space
    NFPackagePart* pPackagePart = s_pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    ASSERT_NE(pPackagePart, nullptr) << "Failed to get package part";

    int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
    if (iEmptyGridNum < 5)
    {
        NFServicePackage::DelAllItemByItemID(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iSuitableBagType);
    }

    // 先添加物品
    int iAddNum = 15;
    iRetCode = NFServicePackage::AddByItemIDAndNum(s_pPlayer, proto_ff::EN_ICR_GM, iItemID, iAddNum, iSuitableBagType, EN_BT_AUTO);
    if (iRetCode != 0)
    {
        // Skip test if failed to add item
        return;
    }

    // 删除格子中的物品
    int iGridIndex = 0;

    iRetCode = NFServicePackage::DelItemByGrid(s_pPlayer, proto_ff::EN_ICR_GM, iGridIndex, iSuitableBagType);

    EXPECT_TRUE(iRetCode == 0 || iRetCode < 0) << "Return code should be valid";
}

// ================================================================================
// Test cases: Virtual money operations
// ================================================================================

/**
 * @brief 测试判断是否为虚拟货币
 */
TEST_F(PackageServiceTestFixture, TestIsVirtualMoney)
{
    // 测试已知的虚拟货币类型
    EXPECT_TRUE(NFItemUtil::IsVirtualMoney(EN_ID_EXP)) << "EXP should be virtual money";
    EXPECT_TRUE(NFItemUtil::IsVirtualMoney(EN_ID_PET_EXP)) << "PET_EXP should be virtual money";
    EXPECT_TRUE(NFItemUtil::IsVirtualMoney(EN_ID_GUILD_BOUNS)) << "GUILD_BOUNS should be virtual money";

    // 测试非虚拟货币类型
    EXPECT_FALSE(NFItemUtil::IsVirtualMoney(999999)) << "Unknown type should not be virtual money";
}

/**
 * @brief 测试虚拟货币增加
 */
TEST_F(PackageServiceTestFixture, TestOnVirtualMoneyInc)
{
    ASSERT_NE(s_pPlayer, nullptr) << "Player object is null";

    // 测试增加经验
    int64_t value = 1000;
    int iRetCode = NFServicePackage::OnVirtualMoneyInc(s_pPlayer, EN_ID_EXP, value, proto_ff::EN_ICR_GM, 0);

    // 根据系统实现，可能返回0或错误码
    EXPECT_TRUE(iRetCode == 0 || iRetCode < 0) << "Return code should be valid";

    // 测试无效值（负数）
    iRetCode = NFServicePackage::OnVirtualMoneyInc(s_pPlayer, EN_ID_EXP, -100, proto_ff::EN_ICR_GM, 0);
    EXPECT_NE(iRetCode, 0) << "Should fail for negative value";

    // 测试无效值（零）
    iRetCode = NFServicePackage::OnVirtualMoneyInc(s_pPlayer, EN_ID_EXP, 0, proto_ff::EN_ICR_GM, 0);
    EXPECT_NE(iRetCode, 0) << "Should fail for zero value";
}

// ================================================================================
// Main test runner function implementation
// ================================================================================

int NFPackageServiceTest::RunAllTests(NFPlayer* pPlayer)
{
    if (pPlayer == nullptr)
    {
        LOG_ERR(0, -1, "Player is null, cannot run package service tests");
        return -1;
    }

    // Set player object to test fixture
    PackageServiceTestFixture::s_pPlayer = pPlayer;
    for (int i = 0; i < ItemDesc::Instance()->GetResNum(); i++)
    {
        auto pDesc = ItemDesc::Instance()->GetDescByIndex(i);
        CHECK_NULL(0, pDesc);
        switch (pDesc->item_type)
        {
            case proto_ff::EN_ITEM_TYPE_BUFF:
            case proto_ff::EN_ITEM_TYPE_PROP:
            case proto_ff::EN_ITEM_TYPE_TITLE:
            case proto_ff::EN_ITEM_TYPE_MATERIAL:
            case proto_ff::EN_ITEM_TYPE_BOX:
            case proto_ff::EN_ITEM_TYPE_GEMSTONE:
            case proto_ff::EN_ITEM_TYPE_PARTNER_EQUIP_STONE:
            case proto_ff::EN_ITEM_TYPE_RANDOM_QUALITY:
            {
                PackageServiceTestFixture::s_vecItemIDs.push_back(pDesc->id);
                break;
            }
            case proto_ff::EN_ITEM_TYPE_EQUIP:
            case proto_ff::EN_ITEM_TYPE_TREASUREMAP:
            case proto_ff::EN_ITEM_TYPE_SKIN:
            case proto_ff::EN_ITEM_TYPE_PARTNER_EQUIP:
            case proto_ff::EN_ITEM_TYPE_BUFF_EQUIP:
            {
                PackageServiceTestFixture::s_vecEquipIDs.push_back(pDesc->id);
                break;
            }
            case proto_ff::EN_ITEM_TYPE_COIN:
            {
                PackageServiceTestFixture::s_vecMoneys.push_back(pDesc->id);
                break;
            }
        }
    }

    std::random_shuffle(PackageServiceTestFixture::s_vecItemIDs.begin(), PackageServiceTestFixture::s_vecItemIDs.end());
    std::random_shuffle(PackageServiceTestFixture::s_vecEquipIDs.begin(), PackageServiceTestFixture::s_vecEquipIDs.end());
    std::random_shuffle(PackageServiceTestFixture::s_vecMoneys.begin(), PackageServiceTestFixture::s_vecMoneys.end());

    LOG_INFO(pPlayer->GetRoleID(), "======================================");
    LOG_INFO(pPlayer->GetRoleID(), "Starting NFServicePackage unit tests");
    LOG_INFO(pPlayer->GetRoleID(), "======================================");

    // Run all tests
    TestBagPageOperations(pPlayer);
    TestMoneyOperations(pPlayer);
    TestAddItemOperations(pPlayer);
    TestGetItemOperations(pPlayer);
    TestDeleteItemOperations(pPlayer);
    TestVirtualMoneyOperations(pPlayer);

    // NFBagPageOpMgr 复杂操作测试
    TestBagPageOpMgrComplexOperations(pPlayer);
    TestBagPageOpMgrBatchOperations(pPlayer);
    TestBagPageOpMgrAdvancedFeatures(pPlayer);
    TestBagPageOpMgrItemMovement(pPlayer);
    //TestBagPageOpMgrGridOperations(pPlayer);
    //TestBagPageOpMgrErrorScenarios(pPlayer);
    TestBagPageOpMgrPerformanceTests(pPlayer);

    LOG_INFO(pPlayer->GetRoleID(), "======================================");
    LOG_INFO(pPlayer->GetRoleID(), "NFServicePackage unit tests completed");
    LOG_INFO(pPlayer->GetRoleID(), "======================================");

    return 0;
}

void NFPackageServiceTest::TestBagPageOperations(NFPlayer* pPlayer)
{
    LOG_INFO(pPlayer->GetRoleID(), ">>> Test bag page operations");

    // Test get equip bag page
    NFBagPage* pBagPage = NFServicePackage::GetBagPage(pPlayer, EN_BPT_EQUIP);
    if (pBagPage != nullptr)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] GetBagPage (equip bag) test passed");
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] GetBagPage (equip bag) test failed");
    }

    // Test get prop bag page
    NFBagPage* pPropPage = NFServicePackage::GetBagPage(pPlayer, EN_BPT_PROP);
    if (pPropPage != nullptr)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] GetBagPage (prop bag) test passed");
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] GetBagPage (prop bag) test failed");
    }
}

void NFPackageServiceTest::TestMoneyOperations(NFPlayer* pPlayer)
{
    LOG_INFO(pPlayer->GetRoleID(), ">>> Test money operations");

    if (PackageServiceTestFixture::s_vecMoneys.empty())
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] No valid money types available for testing");
        return;
    }

    // Use random money type
    int iMoneyType = PackageServiceTestFixture::RandomMoneyType();

    // Test get money object
    Money* pMoney = NFServicePackage::GetMoney(pPlayer, iMoneyType);
    if (pMoney != nullptr)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] GetMoney (money type: {}) test passed", iMoneyType);
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] GetMoney (money type: {}) test failed", iMoneyType);
    }

    // Test get money number
    int64_t llMoney = NFServicePackage::GetMoneyNumber(pPlayer, iMoneyType);
    LOG_INFO(pPlayer->GetRoleID(), "[PASS] GetMoneyNumber test passed, money type: {}, current amount: {}", iMoneyType, llMoney);

    // Test set money number
    int64_t llOldMoney = llMoney;
    int64_t llNewMoney = llOldMoney + 1000;
    int iRetCode = NFServicePackage::SetMoneyNumber(pPlayer, iMoneyType, llNewMoney);
    if (iRetCode == 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] SetMoneyNumber (money type: {}) test passed", iMoneyType);
        // Restore original value
        NFServicePackage::SetMoneyNumber(pPlayer, iMoneyType, llOldMoney);
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] SetMoneyNumber (money type: {}) test failed", iMoneyType);
    }
}

void NFPackageServiceTest::TestAddItemOperations(NFPlayer* pPlayer)
{
    LOG_INFO(pPlayer->GetRoleID(), ">>> Test add item operations");

    NFPackagePart* pPackagePart = pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    if (pPackagePart == nullptr)
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Cannot get package part");
        return;
    }

    // ========== Test 1: Add stackable items ==========
    if (!PackageServiceTestFixture::s_vecItemIDs.empty())
    {
        int iItemID = PackageServiceTestFixture::RandomItemId();
        LOG_INFO(pPlayer->GetRoleID(), "--- Test stackable item (item ID: {}) ---", iItemID);
        int iSuitableBagType = 0;
        int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iSuitableBagType);
        if (iRetCode != 0)
        {
            // Skip test if cannot get suitable bag
            return;
        }

        // Check bag space
        int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
        LOG_INFO(pPlayer->GetRoleID(), "Empty grids remaining: {}", iEmptyGridNum);

        if (iEmptyGridNum < 5)
        {
            LOG_INFO(pPlayer->GetRoleID(), "Bag space insufficient, clearing bag...");
            NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iItemID, iSuitableBagType);
        }

        // Test add stackable item (first add)
        WillAddItemData stItemData;
        stItemData.id = iItemID;
        stItemData.quality = 1;
        int iAddNum = 50;
        int iActualAddNum = 0;

        iRetCode = NFServicePackage::AddToBag(pPlayer, proto_ff::EN_ICR_GM, stItemData, iAddNum, false, &iActualAddNum);
        if (iRetCode == 0)
        {
            LOG_INFO(pPlayer->GetRoleID(), "[PASS] AddToBag (stackable item-first add) test passed, added count: {}", iActualAddNum);

            // Get total item count after adding
            int iTotalNum1 = 0;
            NFServicePackage::GetItemTotalNum(pPlayer, iItemID, iTotalNum1);
            LOG_INFO(pPlayer->GetRoleID(), "Total item count after adding: {}", iTotalNum1);

            // Test stacking: add same item again
            int iAddNum2 = 30;
            int iActualAddNum2 = 0;
            iRetCode = NFServicePackage::AddToBag(pPlayer, proto_ff::EN_ICR_GM, stItemData, iAddNum2, false, &iActualAddNum2);
            if (iRetCode == 0)
            {
                int iTotalNum2 = 0;
                NFServicePackage::GetItemTotalNum(pPlayer, iItemID, iTotalNum2);
                LOG_INFO(pPlayer->GetRoleID(), "[PASS] AddToBag (stackable item-stack test) test passed, added again: {}, total change: {} -> {}", iActualAddNum2, iTotalNum1, iTotalNum2);

                // Verify if stacking is correct
                if (iTotalNum2 == iTotalNum1 + iActualAddNum2)
                {
                    LOG_INFO(pPlayer->GetRoleID(), "[PASS] Item stacking verification passed");
                }
                else
                {
                    LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Item stacking verification failed, expected: {}, actual: {}", iTotalNum1 + iActualAddNum2, iTotalNum2);
                }
            }
            else
            {
                LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] AddToBag (stackable item-stack test) test failed");
            }
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] AddToBag (stackable item) test failed");
        }
    }

    // ========== Test 2: Add equipment (non-stackable) ==========
    if (!PackageServiceTestFixture::s_vecEquipIDs.empty())
    {
        int iEquipID = PackageServiceTestFixture::RandomEquipId();
        LOG_INFO(pPlayer->GetRoleID(), "--- Test equipment (equip ID: {}, non-stackable) ---", iEquipID);
        int iSuitableBagType = 0;
        int iRetCode = NFItemUtil::GetSuitableBag(iEquipID, proto_ff::EN_ICR_GM, iSuitableBagType);
        if (iRetCode != 0)
        {
            // Skip test if cannot get suitable bag
            return;
        }

        // Check equipment bag space
        int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
        LOG_INFO(pPlayer->GetRoleID(), "Equipment bag empty grids: {}", iEmptyGridNum);

        if (iEmptyGridNum < 3)
        {
            LOG_INFO(pPlayer->GetRoleID(), "Equipment bag space insufficient, clearing bag...");
            NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iEquipID, iSuitableBagType);
        }

        // Add few equipment (equipment is non-stackable, each takes one grid)
        WillAddItemData stEquipData;
        stEquipData.id = iEquipID;
        stEquipData.quality = 1;
        int iAddEquipNum = 2; // Only add 2 equipment
        int iActualAddEquipNum = 0;

        iRetCode = NFServicePackage::AddToBag(pPlayer, proto_ff::EN_ICR_GM, stEquipData, iAddEquipNum, false, &iActualAddEquipNum);
        if (iRetCode == 0)
        {
            LOG_INFO(pPlayer->GetRoleID(), "[PASS] AddToBag (equipment) test passed, added count: {}", iActualAddEquipNum);
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] AddToBag (equipment) test failed");
        }
    }

    // ========== Test 3: Add by ID and number ==========
    if (!PackageServiceTestFixture::s_vecItemIDs.empty())
    {
        int iItemID = PackageServiceTestFixture::RandomItemId();
        int iRetCode = NFServicePackage::AddByItemIDAndNum(pPlayer, proto_ff::EN_ICR_GM, iItemID, 10, 0, EN_BT_AUTO);
        if (iRetCode == 0)
        {
            LOG_INFO(pPlayer->GetRoleID(), "[PASS] AddByItemIDAndNum (item ID: {}) test passed", iItemID);
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] AddByItemIDAndNum (item ID: {}) test failed", iItemID);
        }
    }
}

void NFPackageServiceTest::TestGetItemOperations(NFPlayer* pPlayer)
{
    LOG_INFO(pPlayer->GetRoleID(), ">>> Test get item operations");

    if (PackageServiceTestFixture::s_vecItemIDs.empty())
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] No valid item IDs available for testing");
        return;
    }

    // Use random item ID
    int iItemID = PackageServiceTestFixture::RandomItemId();
    int iSuitableBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iSuitableBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    // Add some items first to ensure bag has items
    iRetCode = NFServicePackage::AddByItemIDAndNum(pPlayer, proto_ff::EN_ICR_GM, iItemID, 10, iSuitableBagType, EN_BT_AUTO);
    if (iRetCode != 0)
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[SKIP] Failed to add item for test, error code: {}", iRetCode);
        return;
    }

    // Test get item total number
    int iTotalNum = 0;
    iRetCode = NFServicePackage::GetAllItemTotalNum(pPlayer, iItemID, iTotalNum);
    if (iRetCode == 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] GetBagItemTotalNumByItemID (item ID: {}) test passed, count: {}", iItemID, iTotalNum);
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] GetBagItemTotalNumByItemID (item ID: {}) test failed", iItemID);
    }

    // Test get suitable bag item total number
    int iTotalNum2 = 0;
    iRetCode = NFServicePackage::GetItemTotalNum(pPlayer, iItemID, iTotalNum2);
    if (iRetCode == 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] GetItemTotalNum (item ID: {}) test passed, count: {}", iItemID, iTotalNum2);
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] GetItemTotalNum (item ID: {}) test failed", iItemID);
    }

    // Test get item (prop bag)
    NFGridItem itemOut;
    iRetCode = NFServicePackage::GetItem(pPlayer, iSuitableBagType, 0, &itemOut);
    if (iRetCode == 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] GetItem (grid index: 0) test passed, item ID: {}", itemOut.GetItemID());
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] GetItem test failed");
    }

    // Test get all items
    std::vector<NFGridItem> vecItems;
    iRetCode = NFServicePackage::GetItem(pPlayer, iSuitableBagType, vecItems);
    if (iRetCode >= 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] GetItem (get all items) test passed, item count: {}", vecItems.size());
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] GetItem (get all items) test failed");
    }
}

void NFPackageServiceTest::TestDeleteItemOperations(NFPlayer* pPlayer)
{
    LOG_INFO(pPlayer->GetRoleID(), ">>> Test delete item operations");

    NFPackagePart* pPackagePart = pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    if (pPackagePart == nullptr)
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Cannot get package part");
        return;
    }

    if (PackageServiceTestFixture::s_vecItemIDs.empty())
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] No valid item IDs available for testing");
        return;
    }

    // Use random item ID
    int iItemID = PackageServiceTestFixture::RandomItemId();
    LOG_INFO(pPlayer->GetRoleID(), "--- Test delete item (item ID: {}) ---", iItemID);

    int iSuitableBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iSuitableBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    // Check bag space
    int iEmptyGridNum = pPackagePart->GetEmptyGridNum(iSuitableBagType);
    if (iEmptyGridNum < 5)
    {
        LOG_INFO(pPlayer->GetRoleID(), "Bag space insufficient, clearing bag...");
        NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iItemID, iSuitableBagType);
    }

    // Add some items first for delete test
    int iAddNum = 50;
    iRetCode = NFServicePackage::AddByItemIDAndNum(pPlayer, proto_ff::EN_ICR_GM, iItemID, iAddNum, 0, EN_BT_AUTO);
    if (iRetCode != 0)
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[SKIP] Failed to add item for test, error code: {}", iRetCode);
        return;
    }

    int iTotalBefore = 0;
    NFServicePackage::GetItemTotalNum(pPlayer, iItemID, iTotalBefore);
    LOG_INFO(pPlayer->GetRoleID(), "Total count after adding: {}", iTotalBefore);

    // ========== Test 1: Delete partial items ==========
    int iDelNum = 10;
    int iActualDelNum = 0;
    iRetCode = NFServicePackage::DelItemByItemIDAndNum(pPlayer, proto_ff::EN_ICR_GM, iItemID, iDelNum, &iActualDelNum);
    if (iRetCode == 0)
    {
        int iTotalAfterDel = 0;
        NFServicePackage::GetItemTotalNum(pPlayer, iItemID, iTotalAfterDel);
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] DelItemByItemIDAndNum test passed, deleted count: {}, total change: {} -> {}", iActualDelNum, iTotalBefore, iTotalAfterDel);

        if (iTotalAfterDel == iTotalBefore - iActualDelNum)
        {
            LOG_INFO(pPlayer->GetRoleID(), "[PASS] Count verification after deletion passed");
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Count verification after deletion failed, expected: {}, actual: {}", iTotalBefore - iActualDelNum, iTotalAfterDel);
        }
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] DelItemByItemIDAndNum test failed");
    }

    // ========== Test 2: Delete all items with specified ID ==========
    // Add test items first
    int iItemID2 = PackageServiceTestFixture::RandomItemId();
    LOG_INFO(pPlayer->GetRoleID(), "--- Test delete all items (item ID: {}) ---", iItemID2);
    iRetCode = NFItemUtil::GetSuitableBag(iItemID2, proto_ff::EN_ICR_GM, iSuitableBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }
    iRetCode = NFServicePackage::AddByItemIDAndNum(pPlayer, proto_ff::EN_ICR_GM, iItemID2, 30, iSuitableBagType, EN_BT_AUTO);
    if (iRetCode != 0)
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[SKIP] Failed to add item for test, error code: {}", iRetCode);
        return;
    }

    int iTotalBefore2 = 0;
    NFServicePackage::GetAllItemTotalNum(pPlayer, iItemID2, iTotalBefore2);
    LOG_INFO(pPlayer->GetRoleID(), "Total count before deletion: {}", iTotalBefore2);

    iRetCode = NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iItemID2, iSuitableBagType);
    if (iRetCode == 0)
    {
        int iTotalAfterDelAll = 0;
        NFServicePackage::GetAllItemTotalNum(pPlayer, iItemID2, iTotalAfterDelAll);
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] DelAllItemByItemID test passed, before: {}, after: {}", iTotalBefore2, iTotalAfterDelAll);

        if (iTotalAfterDelAll == 0)
        {
            LOG_INFO(pPlayer->GetRoleID(), "[PASS] All items deleted");
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Delete all items verification failed, still have {} items", iTotalAfterDelAll);
        }
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] DelAllItemByItemID test failed");
    }
}

void NFPackageServiceTest::TestVirtualMoneyOperations(NFPlayer* pPlayer)
{
    LOG_INFO(pPlayer->GetRoleID(), ">>> Test virtual money operations");

    // Test if is virtual money
    bool bIsVirtual = NFItemUtil::IsVirtualMoney(EN_ID_EXP);
    if (bIsVirtual)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] IsVirtualMoney test passed");
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] IsVirtualMoney test failed");
    }

    // Test virtual money increase
    int iRetCode = NFServicePackage::OnVirtualMoneyInc(pPlayer, EN_ID_EXP, 1000, proto_ff::EN_ICR_GM, 0);
    if (iRetCode == 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] OnVirtualMoneyInc test passed");
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] OnVirtualMoneyInc test failed");
    }
}

// ================================================================================
// NFBagPageOpMgr 复杂操作测试
// ================================================================================

void NFPackageServiceTest::TestBagPageOpMgrComplexOperations(NFPlayer* pPlayer)
{
    LOG_INFO(pPlayer->GetRoleID(), ">>> Test NFBagPageOpMgr complex operations");

    if (PackageServiceTestFixture::s_vecItemIDs.empty())
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[SKIP] No valid item IDs available");
        return;
    }

    // ========== Test 1: 复杂添加删除操作 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test complex add-delete operations ---");

    int iItemID1 = PackageServiceTestFixture::RandomItemId();
    int iItemID2 = PackageServiceTestFixture::RandomItemId();

    // 清理测试物品
    NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iItemID1, 0);
    NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iItemID2, 0);

    // 创建背包操作管理器
    NFBagPageOpMgr opMgr(pPlayer, proto_ff::EN_ICR_GM, true);

    // 添加多种物品
    WillAddItemData stItemData1;
    stItemData1.id = iItemID1;

    WillAddItemData stItemData2;
    stItemData2.id = iItemID2;

    // 添加物品1
    int iAddedNum1 = 0;
    int iRetCode = opMgr.AddToBag(stItemData1, 20, &iAddedNum1);
    if (iRetCode == 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Add item1: {} items", iAddedNum1);

        // 添加物品2
        int iAddedNum2 = 0;
        iRetCode = opMgr.AddToBag(stItemData2, 15, &iAddedNum2);
        if (iRetCode == 0)
        {
            LOG_INFO(pPlayer->GetRoleID(), "[PASS] Add item2: {} items", iAddedNum2);

            // 删除部分物品1
            int iDelNum1 = 0;
            iRetCode = opMgr.DelItems(iItemID1, 10, &iDelNum1);
            if (iRetCode == 0)
            {
                LOG_INFO(pPlayer->GetRoleID(), "[PASS] Delete item1: {} items", iDelNum1);

                // 删除所有物品2
                iRetCode = opMgr.DelAllItems(iItemID2);
                if (iRetCode == 0)
                {
                    LOG_INFO(pPlayer->GetRoleID(), "[PASS] Delete all item2");

                    // 提交所有操作
                    iRetCode = opMgr.Commit(true);
                    if (iRetCode == 0)
                    {
                        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Complex operations commit successful");

                        // 验证最终结果
                        int iFinalCount1 = 0, iFinalCount2 = 0;
                        NFServicePackage::GetItemTotalNum(pPlayer, iItemID1, iFinalCount1);
                        NFServicePackage::GetItemTotalNum(pPlayer, iItemID2, iFinalCount2);

                        LOG_INFO(pPlayer->GetRoleID(), "[VERIFY] Final count - item1: {}, item2: {}", iFinalCount1, iFinalCount2);

                        if (iFinalCount1 >= (iAddedNum1 - iDelNum1) && iFinalCount2 == 0)
                        {
                            LOG_INFO(pPlayer->GetRoleID(), "[PASS] Complex operations verification passed");
                        }
                        else
                        {
                            LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Complex operations verification failed");
                        }
                    }
                    else
                    {
                        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Complex operations commit failed");
                    }
                }
                else
                {
                    LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Delete all item2 failed");
                }
            }
            else
            {
                LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Delete item1 failed");
            }
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add item2 failed");
        }
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add item1 failed");
    }

    // ========== Test 2: 跨背包页签操作 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test cross-bag operations ---");

    if (PackageServiceTestFixture::s_vecBagTypes.size() >= 2)
    {
        int iBagType1 = PackageServiceTestFixture::s_vecBagTypes[0];
        int iBagType2 = PackageServiceTestFixture::s_vecBagTypes[1];
        int iRetCode = NFItemUtil::GetSuitableBag(iItemID1, proto_ff::EN_ICR_GM, iBagType1);
        if (iRetCode != 0)
        {
            // Skip test if cannot get suitable bag
            return;
        }

        iRetCode = NFItemUtil::GetSuitableBag(iItemID2, proto_ff::EN_ICR_GM, iBagType2);
        if (iRetCode != 0)
        {
            // Skip test if cannot get suitable bag
            return;
        }

        NFBagPageOpMgr crossOpMgr(pPlayer, proto_ff::EN_ICR_GM, true);

        // 添加背包页签
        std::vector<int> vecBagTypes = {iBagType1, iBagType2};
        iRetCode = crossOpMgr.AddBagPageOp(vecBagTypes);
        if (iRetCode == 0)
        {
            LOG_INFO(pPlayer->GetRoleID(), "[PASS] Add bag pages: {}, {}", iBagType1, iBagType2);

            // 在第一个背包页签添加物品
            int iAddedToBag1 = 0;
            iRetCode = crossOpMgr.AddToBagPage(stItemData1, 10, iBagType1, &iAddedToBag1);
            if (iRetCode == 0)
            {
                LOG_INFO(pPlayer->GetRoleID(), "[PASS] Add to bag1: {} items", iAddedToBag1);

                // 在第二个背包页签添加物品
                int iAddedToBag2 = 0;
                iRetCode = crossOpMgr.AddToBagPage(stItemData2, 8, iBagType2, &iAddedToBag2);
                if (iRetCode == 0)
                {
                    LOG_INFO(pPlayer->GetRoleID(), "[PASS] Add to bag2: {} items", iAddedToBag2);

                    // 提交操作
                    iRetCode = crossOpMgr.Commit(true);
                    if (iRetCode == 0)
                    {
                        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Cross-bag operations commit successful");
                    }
                    else
                    {
                        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Cross-bag operations commit failed");
                    }
                }
                else
                {
                    LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add to bag2 failed");
                }
            }
            else
            {
                LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add to bag1 failed");
            }
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add bag pages failed");
        }
    }
    else
    {
        LOG_INFO(pPlayer->GetRoleID(), "[SKIP] Not enough bag types for cross-bag test");
    }
}

void NFPackageServiceTest::TestBagPageOpMgrBatchOperations(NFPlayer* pPlayer)
{
    LOG_INFO(pPlayer->GetRoleID(), ">>> Test NFBagPageOpMgr batch operations");

    if (PackageServiceTestFixture::s_vecItemIDs.size() < 3)
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[SKIP] Not enough item IDs for batch test");
        return;
    }

    // ========== Test 1: 批量添加多种物品 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test batch add multiple items ---");

    // 准备批量物品数据
    std::vector<WillAddItemData> vecItemData;
    std::vector<int> vecWantAddNum;

    for (int i = 0; i < 3; ++i)
    {
        int iItemID = PackageServiceTestFixture::s_vecItemIDs[i];

        // 清理测试物品
        NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iItemID, 0);

        WillAddItemData stItemData;
        stItemData.id = iItemID;

        vecItemData.push_back(stItemData);
        vecWantAddNum.push_back(5 + i * 2); // 5, 7, 9
    }

    // 创建背包操作管理器
    NFBagPageOpMgr batchOpMgr(pPlayer, proto_ff::EN_ICR_GM, true);

    // 批量添加物品
    std::vector<int> vecAddedNum;
    int iRetCode = batchOpMgr.AddToBag(vecItemData, vecWantAddNum, &vecAddedNum);
    if (iRetCode == 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Batch add successful");

        for (int i = 0; i < 3; ++i)
        {
            LOG_INFO(pPlayer->GetRoleID(), "  Item{}: want={}, added={}", PackageServiceTestFixture::s_vecItemIDs[i], vecWantAddNum[i], vecAddedNum[i]);
        }

        // 提交操作
        iRetCode = batchOpMgr.Commit(true);
        if (iRetCode == 0)
        {
            LOG_INFO(pPlayer->GetRoleID(), "[PASS] Batch operations commit successful");

            // 验证结果
            for (int i = 0; i < 3; ++i)
            {
                int iItemID = PackageServiceTestFixture::s_vecItemIDs[i];
                int iTotalCount = 0;
                NFServicePackage::GetItemTotalNum(pPlayer, iItemID, iTotalCount);
                LOG_INFO(pPlayer->GetRoleID(), "  Final count for item{}: {}", iItemID, iTotalCount);
            }
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Batch operations commit failed");
        }
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Batch add failed");
    }

    // ========== Test 2: 批量删除操作 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test batch delete operations ---");

    NFBagPageOpMgr deleteOpMgr(pPlayer, proto_ff::EN_ICR_GM, true);
    deleteOpMgr.AddAllBagPage();

    // 批量删除物品
    for (int i = 0; i < 3; ++i)
    {
        int iItemID = PackageServiceTestFixture::s_vecItemIDs[i];
        int iDelNum = 0;
        iRetCode = deleteOpMgr.DelItems(iItemID, 3, &iDelNum);
        if (iRetCode == 0)
        {
            LOG_INFO(pPlayer->GetRoleID(), "[PASS] Delete item{}: {} items", iItemID, iDelNum);
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Delete item{} failed", iItemID);
        }
    }

    // 提交删除操作
    iRetCode = deleteOpMgr.Commit(true);
    if (iRetCode == 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Batch delete operations commit successful");
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Batch delete operations commit failed");
    }
}

void NFPackageServiceTest::TestBagPageOpMgrAdvancedFeatures(NFPlayer* pPlayer)
{
    LOG_INFO(pPlayer->GetRoleID(), ">>> Test NFBagPageOpMgr advanced features");

    if (PackageServiceTestFixture::s_vecItemIDs.empty())
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[SKIP] No valid item IDs available");
        return;
    }

    // ========== Test 1: 物品数量查询和充足性检查 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test item count and sufficiency check ---");

    int iItemID = PackageServiceTestFixture::RandomItemId();

    // 清理测试物品
    NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iItemID, 0);

    // 先添加一些物品
    NFBagPageOpMgr addOpMgr(pPlayer, proto_ff::EN_ICR_GM, false);
    WillAddItemData stItemData;
    stItemData.id = iItemID;

    int iAddedNum = 0;
    int iRetCode = addOpMgr.AddToBag(stItemData, 25, &iAddedNum);
    addOpMgr.AddAllBagPage();
    if (iRetCode == 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Added {} items for testing", iAddedNum);

        // 测试物品数量查询
        int iItemCount = 0;
        iRetCode = addOpMgr.GetAllItemNum(iItemID, iItemCount);
        if (iRetCode == 0)
        {
            LOG_INFO(pPlayer->GetRoleID(), "[PASS] Get item count: {}", iItemCount);

            // 测试物品充足性检查
            bool bEnough = false;
            iRetCode = addOpMgr.HaveEnoughAllItem(iItemID, 10, bEnough);
            if (iRetCode == 0)
            {
                LOG_INFO(pPlayer->GetRoleID(), "[PASS] Have enough items (10): {}", bEnough ? "true" : "false");

                // 测试不足的情况
                bEnough = false;
                iRetCode = addOpMgr.HaveEnoughAllItem(iItemID, 100, bEnough);
                if (iRetCode == 0)
                {
                    LOG_INFO(pPlayer->GetRoleID(), "[PASS] Have enough items (100): {}", bEnough ? "true" : "false");
                }
                else
                {
                    LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Check item sufficiency (100) failed");
                }
            }
            else
            {
                LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Check item sufficiency (10) failed");
            }
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Get item count failed");
        }
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add items failed");
    }

    // ========== Test 2: 绑定状态设置 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test bind status settings ---");

    NFBagPageOpMgr bindOpMgr(pPlayer, proto_ff::EN_ICR_GM, false);

    // 测试设置不同的绑定状态
    bindOpMgr.SetBindStatForAdd(EN_BT_FORCE_BIND);
    if (bindOpMgr.GetBindStatForAdd() == EN_BT_FORCE_BIND)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Set bind status to BIND");
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Set bind status to BIND failed");
    }

    bindOpMgr.SetBindStatForAdd(EN_BT_FORCE_NOT_BIND);
    if (bindOpMgr.GetBindStatForAdd() == EN_BT_FORCE_NOT_BIND)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Set bind status to UNBIND");
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Set bind status to UNBIND failed");
    }

    bindOpMgr.SetBindStatForAdd(EN_BT_AUTO);
    if (bindOpMgr.GetBindStatForAdd() == EN_BT_AUTO)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Set bind status to AUTO");
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Set bind status to AUTO failed");
    }

    // ========== Test 3: 操作记录和变更记录 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test operation and change records ---");

    // 添加一些物品
    int iRecordItemID = PackageServiceTestFixture::RandomItemId();
    NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iRecordItemID, 0);

    NFBagPageOpMgr recordOpMgr(pPlayer, proto_ff::EN_ICR_GM, true);

    WillAddItemData stRecordItemData;
    stRecordItemData.id = iRecordItemID;

    int iRecordAddedNum = 0;
    iRetCode = recordOpMgr.AddToBag(stRecordItemData, 10, &iRecordAddedNum);
    if (iRetCode == 0)
    {
        // 删除一些物品
        int iRecordDelNum = 0;
        iRetCode = recordOpMgr.DelItems(iRecordItemID, 3, &iRecordDelNum);
        if (iRetCode == 0)
        {
            // 提交操作
            iRetCode = recordOpMgr.Commit(true);
            if (iRetCode == 0)
            {
                LOG_INFO(pPlayer->GetRoleID(), "[PASS] Record operations completed");

                // 检查操作记录
                const auto& opItemRec = recordOpMgr.GetOpItemRec();
                const auto& itemChangeRec = recordOpMgr.GetItemChangeRec();

                LOG_INFO(pPlayer->GetRoleID(), "Operation records count: {}", opItemRec.size());
                LOG_INFO(pPlayer->GetRoleID(), "Change records count: {}", itemChangeRec.size());

                // 查找我们的物品记录
                auto itOp = opItemRec.find(iRecordItemID);
                if (itOp != opItemRec.end())
                {
                    LOG_INFO(pPlayer->GetRoleID(), "[PASS] Found operation record for item{}: {}", iRecordItemID, itOp->second);
                }

                auto itChange = itemChangeRec.find(iRecordItemID);
                if (itChange != itemChangeRec.end())
                {
                    LOG_INFO(pPlayer->GetRoleID(), "[PASS] Found change record for item{}: {}", iRecordItemID, itChange->second);
                }
            }
            else
            {
                LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Record operations commit failed");
            }
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Record delete operation failed");
        }
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Record add operation failed");
    }
}

void NFPackageServiceTest::TestBagPageOpMgrItemMovement(NFPlayer* pPlayer)
{
    LOG_INFO(pPlayer->GetRoleID(), ">>> Test NFBagPageOpMgr item movement operations");

    if (PackageServiceTestFixture::s_vecItemIDs.empty() || PackageServiceTestFixture::s_vecBagTypes.size() < 2)
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[SKIP] Not enough data for item movement test");
        return;
    }

    // ========== Test 1: 物品移动操作 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test item move operations ---");

    int iItemID = 0;
    int iCount = 0;
    do
    {
        iCount++;
        auto pDesc = ItemDesc::Instance()->GetDesc(PackageServiceTestFixture::RandomEquipId());
        if (pDesc == nullptr)
            break;
        if (pDesc->bag_page_type == EN_BPT_EQUIP)
        {
            iItemID = pDesc->id;
            break;
        }
        if (iCount > 100)
        {
            break;
        }
    }
    while (true);
    int iBagType1 = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iBagType1);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }
    int iBagType2 = EN_BPT_DRESSED_ITEM;

    // 清理测试物品
    NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iItemID, 0);

    // 先添加物品到第一个背包页签
    NFBagPageOpMgr addOpMgr(pPlayer, proto_ff::EN_ICR_GM, true);
    std::vector<int> vecBagTypes = {iBagType1, iBagType2};
    iRetCode = addOpMgr.AddBagPageOp(vecBagTypes);
    if (iRetCode == 0)
    {
        WillAddItemData stItemData;
        stItemData.id = iItemID;

        int iAddedNum = 0;
        iRetCode = addOpMgr.AddToBagPage(stItemData, 1, iBagType1, &iAddedNum);
        if (iRetCode == 0)
        {
            iRetCode = addOpMgr.Commit(true);
            if (iRetCode == 0)
            {
                LOG_INFO(pPlayer->GetRoleID(), "[PASS] Added {} items to bag1 for movement test", iAddedNum);

                // 创建移动操作管理器
                NFBagPageOpMgr moveOpMgr(pPlayer, proto_ff::EN_ICR_GM, true);
                moveOpMgr.AddBagPageOp(vecBagTypes);

                // 测试移动物品
                iRetCode = moveOpMgr.MoveWare(iBagType1, 0, iBagType2);
                if (iRetCode == 0)
                {
                    LOG_INFO(pPlayer->GetRoleID(), "[PASS] Move item from bag{} to bag{}", iBagType1, iBagType2);

                    // 提交移动操作
                    iRetCode = moveOpMgr.Commit(true);
                    if (iRetCode == 0)
                    {
                        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Item movement commit successful");

                        // 验证移动结果
                        int iCount1 = 0, iCount2 = 0;
                        NFServicePackage::GetItemTotalNum(pPlayer, iItemID, iCount1);
                        LOG_INFO(pPlayer->GetRoleID(), "[VERIFY] Item count after movement: {}", iCount1);
                    }
                    else
                    {
                        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Item movement commit failed");
                    }
                }
                else
                {
                    LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Move item failed");
                }
            }
            else
            {
                LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add items commit failed");
            }
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add items to bag1 failed");
        }
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add bag pages failed");
    }

    // ========== Test 2: 物品交换操作 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test item swap operations ---");

    int iItemID1 = PackageServiceTestFixture::RandomItemId();
    iRetCode = NFItemUtil::GetSuitableBag(iItemID1, proto_ff::EN_ICR_GM, iBagType1);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    iCount = 0;
    int iItemID2 = 0;
    do
    {
        auto pDesc = ItemDesc::Instance()->GetDesc(PackageServiceTestFixture::RandomItemId());
        if (pDesc == nullptr)
            break;
        if (pDesc->bag_page_type == iBagType1)
        {
            iItemID2 = pDesc->id;
            break;
        }
        if (iCount > 100)
        {
            break;
        }
    } while (true);



    iBagType2 = EN_BPT_TEMP_STORAGE;

    // 清理测试物品
    NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iItemID1, 0);
    NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iItemID2, 0);

    // 添加两种物品到不同位置
    NFBagPageOpMgr swapAddOpMgr(pPlayer, proto_ff::EN_ICR_GM, true);
    swapAddOpMgr.AddBagPageOp(vecBagTypes);

    WillAddItemData stItemData1, stItemData2;
    stItemData1.id = iItemID1;
    stItemData2.id = iItemID2;

    int iAdded1 = 0, iAdded2 = 0;
    iRetCode = swapAddOpMgr.AddToBagPage(stItemData1, 5, iBagType1, &iAdded1);
    if (iRetCode == 0)
    {
        iRetCode = swapAddOpMgr.AddToBagPage(stItemData2, 3, iBagType2, &iAdded2);
        if (iRetCode == 0)
        {
            iRetCode = swapAddOpMgr.Commit(true);
            if (iRetCode == 0)
            {
                LOG_INFO(pPlayer->GetRoleID(), "[PASS] Added items for swap test");

                // 创建交换操作管理器
                NFBagPageOpMgr swapOpMgr(pPlayer, proto_ff::EN_ICR_GM, true);
                swapOpMgr.AddBagPageOp(vecBagTypes);

                // 测试交换物品
                iRetCode = swapOpMgr.SwapGrid(iBagType1, 0, iBagType2, 0);
                if (iRetCode == 0)
                {
                    LOG_INFO(pPlayer->GetRoleID(), "[PASS] Swap items between bags");

                    // 提交交换操作
                    iRetCode = swapOpMgr.Commit(true);
                    if (iRetCode == 0)
                    {
                        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Item swap commit successful");
                    }
                    else
                    {
                        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Item swap commit failed");
                    }
                }
                else
                {
                    LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Swap items failed");
                }
            }
            else
            {
                LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add items for swap commit failed");
            }
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add item2 for swap failed");
        }
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add item1 for swap failed");
    }
}

void NFPackageServiceTest::TestBagPageOpMgrGridOperations(NFPlayer* pPlayer)
{
    LOG_INFO(pPlayer->GetRoleID(), ">>> Test NFBagPageOpMgr grid operations");

    if (PackageServiceTestFixture::s_vecItemIDs.empty() || PackageServiceTestFixture::s_vecBagTypes.empty())
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[SKIP] Not enough data for grid operations test");
        return;
    }

    // ========== Test 1: 按格子删除物品 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test delete by grid operations ---");

    int iItemID = PackageServiceTestFixture::RandomItemId();
    int iBagType = PackageServiceTestFixture::s_vecBagTypes[0];
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, proto_ff::EN_ICR_GM, iBagType);
    if (iRetCode != 0)
    {
        // Skip test if cannot get suitable bag
        return;
    }

    // 清理测试物品
    NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iItemID, 0);

    // 先添加物品
    NFBagPageOpMgr addOpMgr(pPlayer, proto_ff::EN_ICR_GM, true);
    std::vector<int> vecBagTypes = {iBagType};
    iRetCode = addOpMgr.AddBagPageOp(vecBagTypes);
    if (iRetCode == 0)
    {
        WillAddItemData stItemData;
        stItemData.id = iItemID;

        int iAddedNum = 0;
        iRetCode = addOpMgr.AddToBagPage(stItemData, 15, iBagType, &iAddedNum);
        if (iRetCode == 0)
        {
            // 测试按格子删除物品
            iRetCode = addOpMgr.DelItemByGridIndex(iBagType, 0, 5);
            if (iRetCode == 0)
            {
                LOG_INFO(pPlayer->GetRoleID(), "[PASS] Delete 5 items from grid 0");

                // 提交删除操作
                iRetCode = addOpMgr.Commit(true);
                if (iRetCode == 0)
                {
                    LOG_INFO(pPlayer->GetRoleID(), "[PASS] Grid delete commit successful");

                    // 验证删除结果
                    int iRemainingCount = 0;
                    NFServicePackage::GetItemTotalNum(pPlayer, iItemID, iRemainingCount);
                    LOG_INFO(pPlayer->GetRoleID(), "[VERIFY] Remaining items after grid delete: {}", iRemainingCount);
                }
                else
                {
                    LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Grid delete commit failed");
                }
            }
            else
            {
                LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Delete by grid failed");
            }
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add items for grid test failed");
        }
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add bag page for grid test failed");
    }

    // ========== Test 2: 格子操作边界测试 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test grid boundary operations ---");

    NFBagPageOpMgr boundaryOpMgr(pPlayer, proto_ff::EN_ICR_GM, true);
    boundaryOpMgr.AddBagPageOp(vecBagTypes);

    // 测试无效格子索引
    iRetCode = boundaryOpMgr.DelItemByGridIndex(iBagType, -1, 1);
    if (iRetCode != 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Invalid grid index (-1) correctly rejected");
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Invalid grid index (-1) should be rejected");
    }

    // 测试超出范围的格子索引
    iRetCode = boundaryOpMgr.DelItemByGridIndex(iBagType, 999, 1);
    if (iRetCode != 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Out of range grid index (999) correctly rejected");
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Out of range grid index (999) should be rejected");
    }

    // 测试删除数量为0
    iRetCode = boundaryOpMgr.DelItemByGridIndex(iBagType, 0, 0);
    if (iRetCode == 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Delete 0 items from grid is valid");
    }
    else
    {
        LOG_INFO(pPlayer->GetRoleID(), "[INFO] Delete 0 items from grid returned error: {}", iRetCode);
    }
}

void NFPackageServiceTest::TestBagPageOpMgrErrorScenarios(NFPlayer* pPlayer)
{
    LOG_INFO(pPlayer->GetRoleID(), ">>> Test NFBagPageOpMgr error scenarios");

    // ========== Test 1: 空指针和无效参数测试 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test null pointer and invalid parameters ---");

    // 测试空玩家指针
    NFBagPageOpMgr* pNullPlayerOpMgr = nullptr;
    if (pNullPlayerOpMgr == nullptr)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Null player pointer handled correctly");
    }

    // 测试无效物品ID
    NFBagPageOpMgr invalidOpMgr(pPlayer, proto_ff::EN_ICR_GM, false);
    WillAddItemData stInvalidItemData;
    stInvalidItemData.id = -1; // 无效物品ID

    int iAddedNum = 0;
    int iRetCode = invalidOpMgr.AddToBag(stInvalidItemData, 1, &iAddedNum);
    if (iRetCode != 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Invalid item ID (-1) correctly rejected");
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Invalid item ID (-1) should be rejected");
    }

    // 测试负数数量
    if (PackageServiceTestFixture::s_vecItemIDs.empty())
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[SKIP] No valid item IDs for negative number test");
        return;
    }

    int iItemID = PackageServiceTestFixture::RandomItemId();
    WillAddItemData stItemData;
    stItemData.id = iItemID;

    iRetCode = invalidOpMgr.AddToBag(stItemData, -5, &iAddedNum);
    if (iRetCode != 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Negative item number (-5) correctly rejected");
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Negative item number (-5) should be rejected");
    }

    // ========== Test 2: 背包空间不足测试 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test insufficient bag space ---");

    NFBagPageOpMgr spaceOpMgr(pPlayer, proto_ff::EN_ICR_GM, false);
    stItemData.id = iItemID;

    // 尝试添加大量物品
    iRetCode = spaceOpMgr.AddToBag(stItemData, 99999, &iAddedNum);
    if (iRetCode == 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[INFO] Added {} items (space test)", iAddedNum);
        if (iAddedNum < 99999)
        {
            LOG_INFO(pPlayer->GetRoleID(), "[PASS] Bag space limitation working correctly");
        }
    }
    else
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Insufficient bag space correctly handled");
    }

    // ========== Test 3: 删除不存在的物品 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test delete non-existent items ---");

    NFBagPageOpMgr delOpMgr(pPlayer, proto_ff::EN_ICR_GM, false);
    delOpMgr.AddAllBagPage();

    // 尝试删除不存在的物品
    int iDelNum = 0;
    iRetCode = delOpMgr.DelItems(99999, 10, &iDelNum);
    if (iRetCode == 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[INFO] Delete non-existent item returned: {} deleted", iDelNum);
        if (iDelNum == 0)
        {
            LOG_INFO(pPlayer->GetRoleID(), "[PASS] Delete non-existent item handled correctly");
        }
    }
    else
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Delete non-existent item correctly rejected");
    }

    // ========== Test 4: 重复提交测试 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test duplicate commit ---");

    NFBagPageOpMgr commitOpMgr(pPlayer, proto_ff::EN_ICR_GM, true);
    stItemData.id = iItemID;

    iRetCode = commitOpMgr.AddToBag(stItemData, 5, &iAddedNum);
    if (iRetCode == 0)
    {
        // 第一次提交
        iRetCode = commitOpMgr.Commit(true);
        if (iRetCode == 0)
        {
            LOG_INFO(pPlayer->GetRoleID(), "[PASS] First commit successful");

            // 尝试重复提交
            iRetCode = commitOpMgr.Commit(true);
            if (iRetCode != 0)
            {
                LOG_INFO(pPlayer->GetRoleID(), "[PASS] Duplicate commit correctly rejected");
            }
            else
            {
                LOG_ERR(pPlayer->GetRoleID(), -1, "[FAIL] Duplicate commit should be rejected");
            }
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] First commit failed");
        }
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Add items for commit test failed");
    }
}

void NFPackageServiceTest::TestBagPageOpMgrPerformanceTests(NFPlayer* pPlayer)
{
    LOG_INFO(pPlayer->GetRoleID(), ">>> Test NFBagPageOpMgr performance tests");

    if (PackageServiceTestFixture::s_vecItemIDs.size() < 5)
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "[SKIP] Not enough item IDs for performance test");
        return;
    }

    // ========== Test 1: 大量物品添加性能测试 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test large batch add performance ---");

    // 准备大量物品数据
    std::vector<WillAddItemData> vecItemData;
    std::vector<int> vecWantAddNum;

    for (int i = 0; i < 5; ++i)
    {
        int iItemID = PackageServiceTestFixture::s_vecItemIDs[i];

        // 清理测试物品
        NFServicePackage::DelAllItemByItemID(pPlayer, proto_ff::EN_ICR_GM, iItemID, 0);

        WillAddItemData stItemData;
        stItemData.id = iItemID;

        vecItemData.push_back(stItemData);
        vecWantAddNum.push_back(20 + i * 5); // 20, 25, 30, 35, 40
    }

    // 记录开始时间
    auto startTime = std::chrono::high_resolution_clock::now();

    // 创建批量操作管理器
    NFBagPageOpMgr perfOpMgr(pPlayer, proto_ff::EN_ICR_GM, true);

    // 批量添加物品
    std::vector<int> vecAddedNum;
    int iRetCode = perfOpMgr.AddToBag(vecItemData, vecWantAddNum, &vecAddedNum);

    // 记录添加完成时间
    auto addTime = std::chrono::high_resolution_clock::now();

    if (iRetCode == 0)
    {
        // 提交操作
        iRetCode = perfOpMgr.Commit(true);

        // 记录提交完成时间
        auto commitTime = std::chrono::high_resolution_clock::now();

        if (iRetCode == 0)
        {
            // 计算时间
            auto addDuration = std::chrono::duration_cast<std::chrono::milliseconds>(addTime - startTime);
            auto commitDuration = std::chrono::duration_cast<std::chrono::milliseconds>(commitTime - addTime);
            auto totalDuration = std::chrono::duration_cast<std::chrono::milliseconds>(commitTime - startTime);

            LOG_INFO(pPlayer->GetRoleID(), "[PASS] Performance test completed");
            LOG_INFO(pPlayer->GetRoleID(), "  Add time: {}ms", addDuration.count());
            LOG_INFO(pPlayer->GetRoleID(), "  Commit time: {}ms", commitDuration.count());
            LOG_INFO(pPlayer->GetRoleID(), "  Total time: {}ms", totalDuration.count());

            // 统计添加结果
            int iTotalAdded = 0;
            for (int i = 0; i < 5; ++i)
            {
                LOG_INFO(pPlayer->GetRoleID(), "  Item{}: want={}, added={}", PackageServiceTestFixture::s_vecItemIDs[i], vecWantAddNum[i], vecAddedNum[i]);
                iTotalAdded += vecAddedNum[i];
            }
            LOG_INFO(pPlayer->GetRoleID(), "  Total items added: {}", iTotalAdded);
        }
        else
        {
            LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Performance test commit failed");
        }
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Performance test add failed");
    }

    // ========== Test 2: 大量查询性能测试 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test large query performance ---");

    NFBagPageOpMgr queryPerfOpMgr(pPlayer, proto_ff::EN_ICR_GM, false);
    queryPerfOpMgr.AddAllBagPage();

    // 记录查询开始时间
    auto queryStartTime = std::chrono::high_resolution_clock::now();

    // 执行大量查询
    for (int i = 0; i < 5; ++i)
    {
        int iItemID = PackageServiceTestFixture::s_vecItemIDs[i];

        // 查询物品数量
        int iItemCount = 0;
        queryPerfOpMgr.GetAllItemNum(iItemID, iItemCount);

        // 查询物品是否足够
        bool bEnough = false;
        queryPerfOpMgr.HaveEnoughAllItem(iItemID, 10, bEnough);
    }

    // 记录查询完成时间
    auto queryEndTime = std::chrono::high_resolution_clock::now();
    auto queryDuration = std::chrono::duration_cast<std::chrono::milliseconds>(queryEndTime - queryStartTime);

    LOG_INFO(pPlayer->GetRoleID(), "[PASS] Query performance test completed");
    LOG_INFO(pPlayer->GetRoleID(), "  Query time for 5 items: {}ms", queryDuration.count());

    // ========== Test 3: 大量删除性能测试 ==========
    LOG_INFO(pPlayer->GetRoleID(), "--- Test large delete performance ---");

    NFBagPageOpMgr delPerfOpMgr(pPlayer, proto_ff::EN_ICR_GM, true);
    delPerfOpMgr.AddAllBagPage();

    // 记录删除开始时间
    auto delStartTime = std::chrono::high_resolution_clock::now();

    // 执行大量删除
    for (int i = 0; i < 5; ++i)
    {
        int iItemID = PackageServiceTestFixture::s_vecItemIDs[i];
        int iDelNum = 0;
        delPerfOpMgr.DelItems(iItemID, 5, &iDelNum);
    }

    // 记录删除完成时间
    auto delEndTime = std::chrono::high_resolution_clock::now();
    auto delDuration = std::chrono::duration_cast<std::chrono::milliseconds>(delEndTime - delStartTime);

    // 提交删除操作
    iRetCode = delPerfOpMgr.Commit(true);

    // 记录提交完成时间
    auto delCommitTime = std::chrono::high_resolution_clock::now();
    auto delCommitDuration = std::chrono::duration_cast<std::chrono::milliseconds>(delCommitTime - delEndTime);

    if (iRetCode == 0)
    {
        LOG_INFO(pPlayer->GetRoleID(), "[PASS] Delete performance test completed");
        LOG_INFO(pPlayer->GetRoleID(), "  Delete time: {}ms", delDuration.count());
        LOG_INFO(pPlayer->GetRoleID(), "  Delete commit time: {}ms", delCommitDuration.count());
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), iRetCode, "[FAIL] Delete performance test commit failed");
    }
}

#endif
#endif // NF_DEBUG_MODE

